home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
ALLOC.C
next >
Wrap
Text File
|
1993-11-23
|
30KB
|
1,010 lines
/*======================================================================
* File Name: alloc.c *
* Purpose : memory allocation routines *
* Allocation routines. changed from K&R to the use of TURBO C++ offered *
* routines. This is probably not a very portable solution, but it gives *
* at least some relief when used under (MS)DOS. *
* *
* Date Name Description *
* ---- ---- ----------- *
* 04-apr-1991 AA6HM/DK5DC initial implementation *
* 09-apr-1991 AA6HM/DK5DC added memory record *
* 11-apr-1991 AA6HM/DK5DC added crashdump facility *
* 14-apr-1991 AA6HM/DK5DC changed crashdump to ask Turbo C++ via *
* heapchecknode(),if he agrrees to dump and *
* exit because of a corrupted node *
*=======================================================================*/
#define __ALLOC_C 1
#include <stdio.h>
#include <dos.h>
#include <alloc.h>
#include <fcntl.h> /* for filemodes DK5DC */
#include <io.h> /* for creattemp() */
#include <ctype.h> /* for isprint */
#include <conio.h>
#include "global.h"
#include "config.h"
#include "proc.h"
#include "cmdparse.h"
#include "mbuf.h"
#include "session.h"
#include "files.h"
#include "commands.h" /* for doexit() */
#ifdef __CPLUSPLUS
#define Free 0
#define Used 1
#define Over 2
#endif
/* Free memory threshold, below which things start to happen to conserve
* memory, like garbage collection, source quenches and refusing connects
*/
static int32 Memthresh = (int32)MTHRESH; /* to be sure - db3fl */
static int32 Intalloc = 0; /* Calls to malloc with ints disabled */
static int32 Memfail = 0; /* Count of allocation failures */
static int32 Allocs = 0; /* Total allocations */
static int32 Frees = 0; /* Total frees */
static int32 Intfree = 0; /* Calls to free with ints disabled */
#if(defined(PACKET) || defined(ETHER) || defined(SCC))
static int16 Ibufsize = IBUFSIZE; /* Size to allocate */
static int Nibufs = NIBUFS; /* Number of Int-buffers */
#else
static int16 Ibufsize = 1;
static int Nibufs = 1;
#endif
static int Intqlen = 0; /* Number of free mbufs on Intq */
static int Memwait = 0; /* Number of tasks waiting for memory */
static int Memcold = FALSE; /* controls rebooting when memory goes low */
static struct mbuf *Intq = NULLBUF; /* Mbuf pool for interrupt handlers */
static struct mbuf *Garbq = NULLBUF; /* List of buffers freed at interrupt time */
#ifdef MDEBUG
static int32 Sizes[16];
static FILE *rfp = 0; /* points to memrecord */
static int rflag = 0;
int binver = 0x5010;
#endif
#ifdef MDEBUG
# define PARA 16
# define UNIT 8
# define ALLOC "\xAA" /* marker for alloc */
# define FREE "\x55" /* marker for free */
/*----------------------------------------------------------------------*
* template to access inserted debug info *
*-----------------------------------------------------------------------*/
typedef struct {
unsigned line;
char file[10];
}Hd;
#else
/*----------------------------------------------------------------------*
* template to access Turbo C++'s memory linkages
*-----------------------------------------------------------------------*/
typedef struct {
unsigned np; /* noOfParagraphs in block */
unsigned seg; /* used: link to previous segment */
unsigned backseg,forseg; /* free freelist linkage */
}Id;
#define Hd char
#endif
/*----------------------------------------------------------------------*
* the three variables below are maintained by C++ to mark the start and *
* the end of the used heap *
*-----------------------------------------------------------------------*/
#ifdef __CPLUSPLUS
extern unsigned far __first;
extern unsigned far __last;
extern unsigned far __rover;
static Hd huge * near checkheap __ARGS((void));
#endif
#ifdef MDEBUG
static int near dump __ARGS((Hd huge *cret));
#endif
/*----------------------------------------------------------------------*
* Set the C++ roving memory pointer to the first free block *
*-----------------------------------------------------------------------*/
static void near
_setrover(void)
{
struct heapinfo hp;
hp.ptr = 0;
while(heapwalk(&hp) != _HEAPEND) {
if(hp.in_use == 0) {
__rover = FP_SEG(hp.ptr);
break;
}
}
}
/*----------------------------------------------------------------------*
* Allocate block of 'nb' bytes *
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
void *
mxalloc(char *file,unsigned line,unsigned nb)
#else
void *
mxalloc(unsigned nb)
#endif
{
Hd *node;
#ifdef MDEBUG
unsigned foo = nb;
int i;
struct time stime;
#endif
if(!istate()) {
Intalloc++;
}
/*-------------------------------------------------------------------*
* If memory is below Memthresh, reboot the system. This seemes to be *
* a more secure way to prevent garbage and 'unexpected modes'. *
*--------------------------------------------------------------------*/
if(availmem() == 0) {
if(Memcold) {
void far (*foo) __ARGS((void));
/* FFFF:0000 is hardware reset vector */
foo = MK_FP(0xffff,0);
(*foo)(); /* no return */
} else {
char *arg[3];
arg[1] = "252";
doexit(0,arg,0);
}
}
if(nb == 0) {
return NULL;
}
_setrover();
#ifdef MDEBUG
/*-------------------------------------------------------------------*
* Record the size of this request *
*--------------------------------------------------------------------*/
for(i = 0; i < 16; i++) {
if(foo >= 32768L) {
break;
}
foo <<= 1;
}
Sizes[15-i]++;
/*-------------------------------------------------------------------*
* the calloc() is merely a circumvention, cause I'm unable to find *
* ALL the uninitialized 'next ptr's' in that whole crop of NOS *
* functions. calloc() makes sure to get (zero) initialized memory *
*--------------------------------------------------------------------*/
if((node = calloc(1,nb + PARA)) != 0) {
/*----------------------------------------------------------------*
* insert the line/file info passed when MDEBUG is on *
*-----------------------------------------------------------------*/
strncpy(node->file,file,8);
node->line = line;
/*----------------------------------------------------------------*
* if recording is on, build a record and write it into the file *
*-----------------------------------------------------------------*/
if (rflag) {
unsigned seg;
/*-------------------------------------------------------------*
* use dostime(), cause it calculates much faster than time() *
* and has a granularity of 10 milliseconds *
*--------------------------------------------------------------*/
gettime(&stime);
fwrite(ALLOC,1,1,rfp); /* write the marker */
seg = FP_SEG((char *)node-4); /* alloce'd segment */
fwrite(&stime,sizeof(struct time),1,rfp);
fwrite(&seg,sizeof(unsigned),1,rfp);
fwrite(((char *)node-4),PARA,1,rfp);
}
Allocs++;
return(node+1);
}
#else /* MDEBUG */
if((node = calloc(1,nb)) != 0) {
Allocs++;
return(node);
}
#endif
Memfail++;
return NULL;
}
/*----------------------------------------------------------------------*
* Put memory block back on heap *
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
void
xfree(char *file,unsigned line,void *b)
#else
void
xfree(void *b)
#endif
{
#ifdef __CPLUSPLUS
Hd huge *cret;
#endif
#ifdef MDEBUG
Hd huge *blk = (Hd *)b - 1;
#endif
if(!istate()) {
Intfree++;
}
if(b == NULL) {
return; /* Required by ANSI */
}
#ifdef __CPLUSPLUS
/*-------------------------------------------------------------------*
* make the audit check
*--------------------------------------------------------------------*/
if((cret = checkheap()) != 0) {
dirps();
iostop();
#ifdef MDEBUG
printf("\nfree(): corrupted Node (%Fp) %10.10s %05u proc %s\n\n",
cret,cret->file,cret->line,Curproc->name);
dump(cret); /* POOF!!!!! */
#else
printf("\nfree(): corrupted Node (%Fp) proc %s\n\n",
cret,Curproc->name);
#endif
exit(255);
}
#endif
#ifdef MDEBUG
else if (rflag) {
struct time stime;
unsigned seg = FP_SEG((char *)blk - 4;
gettime(&stime);
fwrite(FREE,1,1,rfp);
fwrite(&stime,sizeof(struct time),1,rfp);
fwrite(&seg,sizeof(unsigned),1,rfp);
fwrite(((char *)blk - 4),PARA,1,rfp);
seg = line;
fwrite(&seg,sizeof(unsigned),1,rfp);
fwrite(file,10,1,rfp);
}
#endif
#ifdef MDEBUG
free((void *)blk);
#else
free(b);
#endif
Frees++;
semrel(&Memwait);
}
#ifdef MDEBUG
/*----------------------------------------------------------------------*
* Dump the memory in case of an error detected by checkheap and exit.. *
* low level routines are used..... *
*-----------------------------------------------------------------------*/
static int near
dump(Hd huge *cret)
{
int fd, seg, fmode;
char huge *para;
extern struct timer *Timers;
struct timer *tp;
int i_state;
char path[MAXPATH];
strcpy(path,getenv("HOME"));
strcat(path,"\\");;
fmode = _fmode; /* preserve filemode */
_fmode = O_BINARY;
if ((fd=creattemp(path,0))<0) {
_fmode = fmode;
return(-1);
}else {
i_state = dirps();
tprintf("Memory dump started...file = %s\n\r",path);
write(fd,&binver,2); /* write version */
write(fd,&__first,2); /* write __first ptr */
write(fd,&__last,2); /* write __last ptr */
write(fd,&__rover,2); /* write __rover ptr */
write(fd,&cret,4); /* save error position */
write(fd,(char *)cret-4,16); /* save suspected header */
/*----------------------------------------------------------------*
* save processing queue ptrs... *
*-----------------------------------------------------------------*/
write(fd,&Curproc,sizeof(struct proc *));
write(fd,&Rdytab,sizeof(struct proc *));
write(fd,&Susptab,sizeof(struct proc *));
write(fd,&Waittab,16*sizeof(struct proc *));
/*----------------------------------------------------------------*
* save the Timerchain..... *
*-----------------------------------------------------------------*/
for (tp = Timers;tp;tp = tp->next)
write(fd,tp,sizeof(struct timer ));
/*----------------------------------------------------------------*
* save session control blocks *
*-----------------------------------------------------------------*/
seg = NSESSIONS;
write(fd,&seg,sizeof(int));
write(fd,Sessions,sizeof(struct session)*Nsessions);
/*----------------------------------------------------------------*
* save the file descriptors, at least the first 16... *
*-----------------------------------------------------------------*/
write(fd,(char *)&_streams,16*sizeof(FILE));
/*----------------------------------------------------------------*
* now dump the whole heap... maybe expanded to whole system *
* sessions,tcb's etc to get a snapshot of the system *
*-----------------------------------------------------------------*/
for (seg = __first;seg<__last;seg++) {
para = MK_FP(seg,0);
write(fd,(void *)para,PARA);
}
close(fd);
}
restore(i_state);
_fmode = fmode;
return(0);
}
#endif
/*----------------------------------------------------------------------*
* This is a very rough check routine. As I dive into the code *
* the routine might be streamlined DK5DC *
* As far as I could find the facts, the C++ memory links are built as *
* follows: *
* 1. Memory is ALWAYS allocated on a paragraph (16 Byte) Basis *
* TC++ ALWAYS returns a address in the form *
* Segment:0004. The first four bytes in the first paragraph are*
* used for size and link informations. The first two bytes *
* contain the size of the block in paragraphs *
* The remaining two bytes contain a segment address pointing *
* to the previous (allocated block) or to (^self). *
* 2. A FREE entry uses two more byte pairs for header information *
* (This caused some bad NOS crashes when some code was running*
* along a linked list, a block was freed, the 'next'pointer *
* was defined as the first member of the structure and NOS *
* tried to access that ptr AFTER freeing the block) *
* Anyway, those two pairs of code contain a backward *
* and forward pointer to its free neighbours. *
*-----------------------------------------------------------------------*/
#ifdef __CPLUSPLUS
static Hd huge * near
checkheap(void)
{
unsigned prev;
unsigned last = __last;
unsigned run = prev = __first;
Id huge *rp = 0;
/*-------------------------------------------------------------------*
* scan the heap *
*--------------------------------------------------------------------*/
while (run < last) {
rp = MK_FP(run,0);
/*----------------------------------------------------------------*
* make the test *
*-----------------------------------------------------------------*/
if (rp->seg != NULL && rp->seg != prev) {
rp = MK_FP(run,4);
/*-------------------------------------------------------------*
* before getting nasty, ask C++ to check again... *
*--------------------------------------------------------------*/
if(heapcheck() < 0) {
rp = MK_FP(prev,0);
return((Hd huge *)((char *)rp+4));
}
}
prev = run;
run += rp->np;
}
return(0);
}
#endif
/*----------------------------------------------------------------------*
* Version of malloc() that waits if necessary for memory to become available *
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
void *
mxallocw(char *file,unsigned line,unsigned nb)
#else
void *
mxallocw(unsigned nb)
#endif
{
void *cp;
semwait(&Memwait,1);
cp = mxalloc(nb);
semrel(&Memwait);
return cp;
}
/*----------------------------------------------------------------------*
* Version of calloc that waits if necessary for memory to become available *
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
void *
cxallocw(char *file,unsigned line,unsigned nelem,unsigned size)
#else
void *
cxallocw(unsigned nelem,unsigned size)
#endif
{
void *cp;
semwait(&Memwait,1);
cp = mxalloc(nelem * size);
semrel(&Memwait);
return cp;
}
/*----------------------------------------------------------------------*
* Copy a string to a malloc'ed buffer. Turbo C has this one in its *
* library, but it doesn't call mallocw() and can therefore return NULL. *
* NOS uses of strdup() generally don't check for NULL, so they need this*
* one. *
* *
* Changed the name to strxdup and added the file/line pair insertion. *
* Otherwise only the malloc() would be recorded, which is always inside *
* strxdup() and not the strdup location itself. *
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
char *
strxdup(char *file,unsigned line,const char *s)
#else
char *
strxdup(const char *s)
#endif
{
char *out;
int len = strlen(s);
if(s == NULLCHAR || len == 0) {
return NULLCHAR;
}
semwait(&Memwait,1);
out = mxalloc(len+1);
semrel(&Memwait);
/* This is probably a tad faster than strcpy, since we know the len */
memcpy(out,s,len);
return out;
}
/* Check available memory */
int
availmem()
{
return ((Memthresh * 2) < coreleft());
}
#ifdef MDEBUG
/*----------------------------------------------------------------------*
*----------------------------------------------------------------------*/
static int
dorefiq(int argc,char **argv,void *p)
{
struct mbuf *bp = 0, *bp1 = 0;
int i_state;
if(Garbq != NULLBUF){
i_state = dirps(); /* critical section */
bp = Garbq;
Garbq = NULLBUF;
restore(i_state);
free_p(bp);
}
_setrover();
i_state = dirps(); /* critical section */
bp1 = Intq;
Intq = NULLBUF;
restore(i_state);
Intqlen = 0;
refiq();
free_p(bp1);
return 0;
}
#endif
void
refiq(void)
{
struct mbuf *bp;
int i_state;
/* Empty the garbage */
if(Garbq != NULLBUF) {
i_state = dirps();
bp = Garbq;
Garbq = NULLBUF;
restore(i_state);
free_p(bp);
}
/* Replenish interrupt buffer pool */
while(Intqlen < Nibufs) {
bp = alloc_mbuf(Ibufsize);
i_state = dirps();
bp->next = Intq;
Intq = bp;
restore(i_state);
Intqlen++;
}
}
/* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
* are enabled, use the regular heap. If they're off, use the special
* interrupt buffer pool.
*/
#ifdef MDEBUG
struct mbuf *
alloc_mbuf(char *file,unsigned line, int16 size)
#else
struct mbuf *
alloc_mbuf(int16 size)
#endif
{
struct mbuf *bp;
if(istate()) {
/* Interrupts are enabled, use the heap normally */
bp = mxallocw((unsigned)(size + sizeof(struct mbuf)));
if((bp->size = size) != 0) {
bp->data = (char *)(bp + 1);
}
bp->refcnt++;
bp->next = NULLBUF;
} else {
/* Interrupts are off, use special interrupt buffer pool */
if(size > Ibufsize) {
#if(!(defined PACKET) && !(defined ETHER) && !(defined SCC))
Ibufsize = size;
}
#else
char *arg[3];
arg[1] = "253";
printf("\nInterrupt buffer overflow (size %u def %u)\n\n",size,Ibufsize);
doexit(0,arg,0);
} else
#endif
if(Intq == NULLBUF) {
Nibufs++;
bp = mxallocw(Ibufsize + sizeof(struct mbuf));
bp->size = Ibufsize;
bp->data = (char *)(bp + 1);
bp->refcnt++;
bp->next = Intq;
Intq = bp;
} else {
bp = Intq;
Intq = bp->next;
bp->next = NULLBUF;
Intqlen--;
}
}
return bp;
}
/* Decrement the reference pointer in an mbuf. If it goes to zero,
* free all resources associated with mbuf.
* Return pointer to next mbuf in packet chain
*/
struct mbuf *
#ifdef MDEBUG
free_mbuf(char *file,unsigned line,struct mbuf *bp)
#else
free_mbuf(struct mbuf *bp)
#endif
{
struct mbuf *bp1 = bp->next;
if(bp == NULLBUF) {
return NULLBUF;
}
if(bp->dup != NULLBUF) {
free_mbuf(bp->dup); /* Follow indirection */
bp->dup = NULLBUF;
}
/* Decrement reference count. If it has gone to zero, free it. */
if(--bp->refcnt <= 0) {
if(istate()) {
xfree(bp);
} else {
/* If the interrupt pool isn't full and this buffer
* appears to have come from it, put it back.
* Otherwise put it on the garbage list where it
* will be freed by refiq() later with interrupts
* enabled.
*
* This test handles the common special case of
* an interrupt handler allocating a buffer and
* then freeing it before returning (e.g., due to
* a receive abort or CRC failure).
*/
bp->refcnt = 1; /* Adjust */
if(bp->size == Ibufsize && Intqlen < Nibufs) {
bp->anext = NULLBUF;
bp->data = (char *)(bp + 1);
bp->cnt = 0;
bp->next = Intq;
Intq = bp;
Intqlen++;
} else {
bp->next = Garbq;
Garbq = bp;
}
}
}
return bp1;
}
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
#ifdef MDEBUG
int
openmemrec(char *name)
{
if((rfp = Fopen(name,"w+b")) == NULLFILE) {
tprintf("Unable to open record file %s\n\r",name);
return(-1);
}
fprintf(rfp,"THIS FILE CONTAINS BINARY DATA... use ANALMEM \n\r\x1a");
fwrite(&binver,sizeof(int),1,rfp);
tprintf("record Memory allocations into %s\n\r",name);
rflag = 1;
return(0);
}
#endif
#ifdef MDEBUG
/* Convert byte to two ascii-hex characters */
static void near
ctohex(char *buf,int16 c)
{
static char hex[] = "0123456789abcdef";
*buf++ = hex[hinibble(c)];
*buf = hex[lonibble(c)];
}
/* Print a buffer up to 16 bytes long in formatted hex with ascii
* translation, e.g.,
* 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
*/
static void near
fmtline(FILE *fp,int16 addr,char *buf,int16 len,int type)
{
char line[81], *aptr, *cptr, c;
memset(line,' ',sizeof(line));
ctohex(line,hibyte(addr));
ctohex(line+2,lobyte(addr));
aptr = &line[6];
cptr = &line[55];
while(len-- != 0){
c = *buf++;
ctohex(aptr,uchar(c));
aptr += 3;
c &= 0x7f;
*cptr++ = isprint(uchar(c)) ? c : '.';
}
*cptr++ = '\0';
if (type)
fprintf(fp,"%s\n\r",line);
else
tprintf("%s\n",line);
if (fp)
fwrite(line,1,(unsigned)(cptr-line),fp);
}
#endif
#ifdef __CPLUSPLUS
static int near
_checkok(void)
{
if(heapcheck() != _HEAPOK) {
tputs("Heap doesn't check ok\n");
return(0);
}
return 1;
}
#endif
#ifdef __CPLUSPLUS
/*-----------------------------------------------------------------------*/
static int near
getheap(int flag)
{
struct heapinfo hp;
int i = 0;
hp.ptr = 0; /* start at the beginning */
while(1) {
if (heapwalk(&hp) == _HEAPEND) {
break;
}
#ifdef MDEBUG
if(flag == Over) {
int j;
for(j = 0; j < hp.size/16; j += 2) {
if (i == 0) {
tprintf("%04x ",FP_SEG(hp.ptr) + j);
}
tputs(hp.in_use ? "+" : "-");
if(++i == 72) {
i = 0;
tputs("\n");
}
}
} else
#endif
if(hp.in_use == flag) {
tprintf("%4x %5lu",FP_SEG(hp.ptr),hp.size);
if(++i == 6) {
i = 0;
tputs("\n");
} else {
tputs(" | ");
}
}
}
tputs("\nEnd of list\n");
return 0;
}
#endif
/* ------------------------ Memory subcmds ---------------------------- */
#ifdef MDEBUG
static char far *DumpAddr = NULL; /* Memory dump pointer */
int
domdump(int argc,char **argv,void *p)
{
char *addr;
unsigned int i, len = 8 * 16; /* default is 8 lines of hex dump*/
int seg;
if((argc > 3 && DumpAddr == NULL) || (argc < 2 && DumpAddr == 0)) {
tputs("Usage: dump <segment|.> [decimal range]\n");
return 0;
}
if(argv[1][0] == '.' || argc == 1)
addr = DumpAddr; /* Use last end address */
else
#ifdef MEBUG
addr = (char *)(shtop(argv[1]))-16; /* get address of item being dumped */
#else
addr = (char *)(shtop(argv[1]))-4; /* get address of item being dumped */
#endif
seg = FP_SEG(addr);
if(argc == 3) {
len = atoi(argv[2]);
len = ((len + 15) >> 4) << 4; /* round up to modulo 16 */
}
if(len < 1) len = 1;
if(len > 256) len = 256;
tprintf("Main Memory Dump Of Location %Fp\n"
"Addr (offset) Hexadecimal Ascii\n",
addr);
for(i = 0; i < len; i += 16)
fmtline((FILE *)0,seg++, (char *)(addr+i),16,0);
DumpAddr = MK_FP(seg,0); /* update address */
return 0;
}
#endif
static int
docoldst(int argc,char **argv,void *p)
{
return setbool(&Memcold,"Reboot",argc,argv);
}
#ifdef __CPLUSPLUS
/*----------------------------------------------------------------------*
* Print heap free list *
*-----------------------------------------------------------------------*/
static int
dofreelist(int argc,char **argv,void *p)
{
if (!_checkok()) {
return -1;
}
return (getheap(Free));
}
#endif
#if(defined(PACKET) || defined(ETHER) || defined(SCC))
static int
doibufsize(int argc,char **argv,void *p)
{
return setintrc(&Ibufsize,"Int buffer size",argc,argv,0,MAXINT16);
}
static int
donibufs(int argc,char **argv,void *p)
{
return setint(&Nibufs,"Int pool buffers",argc,argv);
}
#endif
#if((defined __CPLUSPLUS) && defined(MDEBUG))
static int
doOverview(int argc,char **argv,void *envp)
{
if (!_checkok()) {
return -1;
}
return (getheap(Over));
}
#endif
#ifdef MDEBUG
static int
dorecord(int argc,char **argv,void *p)
{
if (argc < 2) {
tprintf("Memory recording %s\n", rfp ? "on" : "off");
return(0);
}
if (!stricmp(argv[1],"off")) {
if (rflag) {
Fclose(rfp);
rflag=0;
}
return(0);
}
if (rfp) {
Fclose (rfp);
rflag=0;
}
openmemrec(argv[1]);
return(0);
}
#endif
#ifdef MDEBUG
static int
dosizes(int argc,char **argv,void *p)
{
int i;
for(i = 0; i < 16; i += 4) {
tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
1 << i,Sizes[i],2 << i,Sizes[i+1],
4 << i,Sizes[i+2],8 << i,Sizes[i+3]);
}
return 0;
}
#endif
#ifdef MDEBUG
static int
dosnap(int argc,char **argv,void *p)
{
Hd cret;
memset(&cret,0,sizeof(Hd));
strcpy(cret.file,"SnapDump");
if (!dump(&cret)) {
tputs("Dump successfully written...\n");
} else {
tputs("Can't open Dumpfile...\n");
}
return 0;
}
#endif
/*----------------------------------------------------------------------*
* Print heap stats *
*-----------------------------------------------------------------------*/
static int
dostat(int argc,char **argv,void *p)
{
tprintf("coreleft %lu allocs %lu frees %lu diff %lu invalid %lu\n"
"int-off calls to alloc %lu free %lu\n",
coreleft(),Allocs,Frees,Allocs-Frees,Memfail,Intalloc,Intfree);
#if(defined(PACKET) || defined(ETHER) || defined(SCC))
tprintf("Intqlen %u Ibufsize %u\n",Intqlen,Ibufsize);
#endif
return 0;
}
static int
dothresh(int argc,char **argv,void *p)
{
return setlong(&Memthresh,"Mem threshold (bytes)",argc,argv);
}
#if((defined __CPLUSPLUS) && defined(MDEBUG))
/*----------------------------------------------------------------------*
* Print heap used list *
*-----------------------------------------------------------------------*/
static int
dousedlist(int argc,char **argv,void *p)
{
if (!_checkok()) {
return -1;
}
return (getheap(Used));
}
#endif
/* ------------------------ Memory subcmd-parser ------------------------- */
int
domem(int argc,char **argv,void *p)
{
struct cmds Memcmds[] = {
#ifdef MDEBUG
{"dump", domdump, 0, 0, NULLCHAR},
#endif
#ifdef __CPLUSPLUS
{"freelist", dofreelist, 0, 0, NULLCHAR},
#endif
#if(defined(PACKET) || defined(ETHER) || defined(SCC))
{"ibufsize", doibufsize, 0, 0, NULLCHAR},
{"nibufs", donibufs, 0, 0, NULLCHAR},
#endif
#if((defined __CPLUSPLUS) && defined(MDEBUG))
{"overview", doOverview, 0, 0, NULLCHAR},
#endif
{"reboot", docoldst, 0, 0, NULLCHAR},
#ifdef MDEBUG
{"record", dorecord, 0, 0, NULLCHAR},
{"refiq", dorefiq, 0, 0, NULLCHAR},
{"sizes", dosizes, 0, 0, NULLCHAR},
{"snap", dosnap, 0, 2, "snap start"},
#endif
{"status", dostat, 0, 0, NULLCHAR},
{"thresh", dothresh, 0, 0, NULLCHAR},
#if((defined __CPLUSPLUS) && defined(MDEBUG))
{"usedlist", dousedlist, 0, 0, NULLCHAR},
#endif
{NULLCHAR},
};
return subcmd(Memcmds,argc,argv,p);
}